美文网首页
Android 拍照及相册选图的那些坑

Android 拍照及相册选图的那些坑

作者: ChineseBoy | 来源:发表于2017-03-23 17:56 被阅读1043次

    原因:android手机厂商太多,ROM定制化太严重,给我们码农带了诸多不便。

    Android的拍照功能的实现:

    1.调用系统的相机:

    步骤1:
     public void openCamera(View view) {
            Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            mImagePath = FileUtil.genSystemCameraPhotoPath();
            intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(mImagePath)));
            startActivityForResult(intent, REQUST_CODE_CAMERA);
      } 
    
     case R.id.button1://第一种方法,获取压缩图 
          Intent intent1 = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 
          // 启动相机 
          startActivityForResult(intent1, REQUEST_THUMBNAIL); 
          break; 
        case R.id.button2://第二种方法,获取原图 
          Intent intent2 = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 
          Uri uri = Uri.fromFile(new File(picPath)); 
          //为拍摄的图片指定一个存储的路径 
          intent2.putExtra(MediaStore.EXTRA_OUTPUT, uri); 
          startActivityForResult(intent2, REQUEST_ORIGINAL); 
          break; 
    
    步骤2:
     @Override 
      protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
        super.onActivityResult(requestCode, resultCode, data); 
        if (resultCode == RESULT_OK) { 
          if (requestCode == REQUEST_THUMBNAIL) {//对应第一种方法 
            /** 
             * 通过这种方法取出的拍摄会默认压缩,因为如果相机的像素比较高拍摄出来的图会比较高清, 
             * 如果图太大会造成内存溢出(OOM),因此此种方法会默认给图片压缩 ,坦白说拿到的就是一个缩略                                      图
             */ 
            Bundle bundle = data.getExtras(); 
            Bitmap bitmap = (Bitmap) bundle.get("data"); 
            mImageView.setImageBitmap(bitmap); 
          } 
          else if(resultCode == REQUEST_ORIGINAL){//对应第二种方法 
            /** 
             * 这种方法是通过内存卡的路径进行读取图片,所以的到的图片是拍摄的原图 
             */ 
              result = BitmapFactory.decodeFile(picPath);
            }
          } 
        } 
      } 
    

    2.自定义的相机:

    这个就简单提下
    a.新建一个class extends SurfaceView
    b.在其构造方法里面init一些基本的属性,增加回调 getHolder().addCallback(callback);

    private SurfaceHolder.Callback callback = new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                try {
                    openCamera(mCameraFacing); // 1.打开相机
                    initParameters(); // 2.设置相机参数
                    mCamera.setPreviewDisplay(getHolder()); // 3.设置预览显示的Surface
                } catch (Exception e) {
                    Toast.makeText(getContext(), "打开相机失败", Toast.LENGTH_SHORT).show();
                }
            }
    
            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                updateCamera(); // 4.更新相机属性,每次更换分辨率需要更新的操作,包括设置预览大小和方向,开始预览
            }
    
            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                releaseCamera(); // 5.释放相机资源
            }
        };
    

    c.差不多就a,b了,哈哈。。。

    这里只说下可能出现的旋转问题(比如三星七八手机逆时针旋转了90度):
    既然照片存储的时候是歪的,那我们显示的时候就必须转正了,如何操作呢?

    请看下步:

    ----------------->>>>>>> 旋转问题全家桶 <<<<<<<--------------------

    法子1:旋转JPEG byte[]类型的图片(适合自定义相机拍出来回调的照片,PictureCallback里面)
    //  在 Android 4.1.1 的 Camera 源码中找到
        // Returns the degrees in clockwise. Values are 0, 90, 180, or 270.
        public static int getOrientation(byte[] jpeg) {
            if (jpeg == null) {
                return 0;
            }
    
            int offset = 0;
            int length = 0;
    
            // ISO/IEC 10918-1:1993(E)
            while (offset + 3 < jpeg.length && (jpeg[offset++] & 0xFF) == 0xFF) {
                int marker = jpeg[offset] & 0xFF;
    
                // Check if the marker is a padding.
                if (marker == 0xFF) {
                    continue;
                }
                offset++;
    
                // Check if the marker is SOI or TEM.
                if (marker == 0xD8 || marker == 0x01) {
                    continue;
                }
                // Check if the marker is EOI or SOS.
                if (marker == 0xD9 || marker == 0xDA) {
                    break;
                }
    
                // Get the length and check if it is reasonable.
                length = pack(jpeg, offset, 2, false);
                if (length < 2 || offset + length > jpeg.length) {
                    return 0;
                }
    
                // Break if the marker is EXIF in APP1.
                if (marker == 0xE1 && length >= 8 &&
                        pack(jpeg, offset + 2, 4, false) == 0x45786966 &&
                        pack(jpeg, offset + 6, 2, false) == 0) {
                    offset += 8;
                    length -= 8;
                    break;
                }
    
                // Skip other markers.
                offset += length;
                length = 0;
            }
    
            // JEITA CP-3451 Exif Version 2.2
            if (length > 8) {
                // Identify the byte order.
                int tag = pack(jpeg, offset, 4, false);
                if (tag != 0x49492A00 && tag != 0x4D4D002A) {
                    return 0;
                }
                boolean littleEndian = (tag == 0x49492A00);
    
                // Get the offset and check if it is reasonable.
                int count = pack(jpeg, offset + 4, 4, littleEndian) + 2;
                if (count < 10 || count > length) {
                    return 0;
                }
                offset += count;
                length -= count;
    
                // Get the count and go through all the elements.
                count = pack(jpeg, offset - 2, 2, littleEndian);
                while (count-- > 0 && length >= 12) {
                    // Get the tag and check if it is orientation.
                    tag = pack(jpeg, offset, 2, littleEndian);
                    if (tag == 0x0112) {
                        // We do not really care about type and count, do we?
                        int orientation = pack(jpeg, offset + 8, 2, littleEndian);
                        switch (orientation) {
                            case 1:
                                return 0;
                            case 3:
                                return 180;
                            case 6:
                                return 90;
                            case 8:
                                return 270;
                        }
                        return 0;
                    }
                    offset += 12;
                    length -= 12;
                }
            }
            return 0;
        } 
    
    法子2:旋转从指定Path拿出来的图片
    public static int readPictureDegree(String path) {
            int degree = 0;
            try {
                ExifInterface exifInterface = new ExifInterface(path);
                int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                        ExifInterface.ORIENTATION_NORMAL);
                switch (orientation) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
                case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
                    degree = 0;
                    break;
                case ExifInterface.ORIENTATION_FLIP_VERTICAL:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_TRANSPOSE:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_TRANSVERSE:
                    degree = 270;
                    break;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            return degree;
        }
    
    法子3:旋转原始预览数据NV21(相机预览回调函数PreviewCallback)
    private byte[] rotateYUV420Degree90(byte[] data, int imageWidth, int imageHeight)
        {
            byte [] yuv = new byte[imageWidth*imageHeight*3/2];
            // Rotate the Y luma
            int i = 0;
            for(int x = 0;x < imageWidth;x++)
            {
                for(int y = imageHeight-1;y >= 0;y--)
                {
                    yuv[i] = data[y*imageWidth+x];
                    i++;
                }
            }
            // Rotate the U and V color components
            i = imageWidth*imageHeight*3/2-1;
            for(int x = imageWidth-1;x > 0;x=x-2)
            {
                for(int y = 0;y < imageHeight/2;y++)
                {
                    yuv[i] = data[(imageWidth*imageHeight)+(y*imageWidth)+x];
                    i--;
                    yuv[i] = data[(imageWidth*imageHeight)+(y*imageWidth)+(x-1)];
                    i--;
                }
            }
            return yuv;
        }
    
    法子4:旋转的就是一个bitmap
    @Override  
    public void onPictureTaken(byte[] data, Camera camera) {  
       Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);  
       Matrix matrix = new Matrix();  
       matrix.preRotate(rotate);  
       bitmap = Bitmap.createBitmap(bitmap ,0,0, bitmap .getWidth(), bitmap
    .getHeight(),matrix,true);  
    };
    

    旋转完后可能还会有个镜像的问题(比如前置的摄像头)

    Matrix matrix = new Matrix();
    matrix.postScale(-1, 1);
    bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
    

    拍照的坑就赞告一段落了。休息一会儿吧,骚年。生命诚可贵!!!

    ====================================================================

    Android的图库选图的坑:

    相关文章

      网友评论

          本文标题:Android 拍照及相册选图的那些坑

          本文链接:https://www.haomeiwen.com/subject/dletottx.html