您的位置:首页 > 移动开发 > Android开发

Android开发官方文档---Capturing Photos

2015-12-24 17:14 495 查看
如果应用要使用Camera,添加<uses-feature>标签

<manifest ...> 

    <uses-featureandroid:name="android.hardware.camera" 

                  android:required="true" /> 

    ... 

</manifest>

如果Camera是应用使用到的功能但不是必要的就可以设置required属性为false

在应用里面可以调用hasSystemFeature(PackageManager.FEATURE_CAMERA) 决定是否使用Camera功能。

 

Android调用其他应用的功能需要三步:

(1)使用 Intent 描述想要的操作

static final intREQUEST_IMAGE_CAPTURE = 1; 

 

private voiddispatchTakePictureIntent() { 

    Intent takePictureIntent = newIntent(MediaStore.ACTION_IMAGE_CAPTURE); 

    if(takePictureIntent.resolveActivity(getPackageManager()) != null) { 

        startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE); 

    } 

}

 

(2)调用Activity

调用startActivityForResult()之前为了安全先调用resolveActivity() 获取是否有Activity可以处理Intent的操作

(3)处理返回的数据

调用系统的Camera 会返回一个Intent,里面的data键值为一张小bitmap.这小Bitmap只是原图的压缩版.

重写 onActivityResult 方法获取返回的数据

@Override 

protected voidonActivityResult(int requestCode, int resultCode, Intent data) { 

    if (requestCode ==REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) { 

        Bundleextras = data.getExtras(); 

        BitmapimageBitmap = (Bitmap) extras.get("data"); 

        mImageView.setImageBitmap(imageBitmap); 

    } 

}

 

获取原图:

需要提供一个让Camera保存原图的文件,可以把图片添加到公共的存储区或自己应用的私有区域

getExternalStoragePublicDirectory()       获取外存储公共区域路径

getExternalFilesDir()     获取私有外存储区域路径

步骤:

(1)设置读写外存储权限,4.3版本以下需要添加WRITE_EXTERNAL_STORAGE权限,4.4之后不需要,因为外存储区域的文件都是应用私有的.添加maxSdkVersion属性表明4.3 以下版本需要该权限.

<manifest...> 

    <uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE" 

                     android:maxSdkVersion="18"/> 

    ... 

</manifest>

 

(2)创建文件

StringmCurrentPhotoPath; 

 

private FilecreateImageFile() throws IOException { 

    // Create an image file name 

    String timeStamp = newSimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); 

    String imageFileName ="JPEG_" + timeStamp + "_"; 

    File storageDir =Environment.getExternalStoragePublicDirectory( 

            Environment.DIRECTORY_PICTURES); 

    File image =File.createTempFile( 

             imageFileName,  /*prefix */ 

             ".jpg",         /* suffix */ 

             storageDir      /* directory */ 

    ); 

 

    // Save a file: path for use withACTION_VIEW intents 

    mCurrentPhotoPath = "file:" +image.getAbsolutePath(); 

    return image; 

}

 

(3) 现在 Intent 这样写

private voiddispatchTakePictureIntent() { 

    Intent takePictureIntent = newIntent(MediaStore.ACTION_IMAGE_CAPTURE); 

    // Ensure that there's a cameraactivity to handle the intent 

    if (takePictureIntent.resolveActivity(getPackageManager())!= null) { 

        //Create the File where the photo should go 

        FilephotoFile = null; 

        try{ 

            photoFile = createImageFile(); 

        }catch (IOException ex) { 

            // Error occurred while creating the File 

            ... 

       } 

        //Continue only if the File was successfully created 

        if(photoFile != null) { 

            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, 

                   Uri.fromFile(photoFile)); 

            startActivityForResult(takePictureIntent,REQUEST_TAKE_PHOTO); 

       } 

    } 

}

 

让其它应用扫描到自己私有的图片

因为保存在 getExternalFilesDir() 路径的图片不能被其他图片浏览软件访问,下面是简单的解决方案:

这种方式添加私有的图片到图片浏览器的数据库,让图片浏览器都能扫描到自己的私有图片.

private voidgalleryAddPic() { 

    IntentmediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); 

    File f= new File(mCurrentPhotoPath); 

    UricontentUri = Uri.fromFile(f); 

    mediaScanIntent.setData(contentUri); 

   this.sendBroadcast(mediaScanIntent); 

}

 

//如果显示过多的图片内存不够用的话,可以对图片进行缩小来适应显示的区域,从而减少使用原图造成的内存不够情况。

private void setPic(){ 

    // Get the dimensions of theView 

    int targetW =mImageView.getWidth(); 

    int targetH =mImageView.getHeight(); 

 

    // Get the dimensions of thebitmap 

    BitmapFactory.Options bmOptions =new BitmapFactory.Options(); 

   bmOptions.inJustDecodeBounds = true; 

   BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions); 

    int photoW =bmOptions.outWidth; 

    int photoH =bmOptions.outHeight; 

 

    // Determine how much to scale downthe image 

    int scaleFactor =Math.min(photoW/targetW, photoH/targetH); 

 

    // Decode the image file into aBitmap sized to fill the View 

   bmOptions.inJustDecodeBounds = false; 

   bmOptions.inSampleSize = scaleFactor; 

   bmOptions.inPurgeable = true; 

 

    Bitmap bitmap =BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions); 

   mImageView.setImageBitmap(bitmap); 

}

 

调用系统Camera录制图像

第一步:获取Camera权限

<manifest ...> 

    <uses-featureandroid:name="android.hardware.camera" 

                  android:required="true" /> 

    ... 

</manifest>

如果设备没有Camera,为了可以在Google 应用商店也可以下载,可以设置 required 属性为false,在没有Camera的设备使用程序的时候要判断hasSystemFeature(PackageManager.FEATURE_CAMERA)是否Camera存在进行功能开启和关闭。

 

第二步:设置Intent

static final intREQUEST_VIDEO_CAPTURE = 1; 

 

private voiddispatchTakeVideoIntent() { 

    Intent takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); 

    if(takeVideoIntent.resolveActivity(getPackageManager()) != null) { //先判断是否有应用处理该Intent请求

        startActivityForResult(takeVideoIntent, REQUEST_VIDEO_CAPTURE); 

    } 

}

第三步:处理返回结果

返回的是Video的存储位置Uri

@Override 

protected voidonActivityResult(int requestCode, int resultCode, Intent data) { 

    if (requestCode ==REQUEST_VIDEO_CAPTURE && resultCode == RESULT_OK) { 

        UrivideoUri = intent.getData(); 

       mVideoView.setVideoURI(videoUri);  //使用VideoView播放Video

    } 

}

 

控制Camera 对象

(1)使用open()获取Camera对象

private booleansafeCameraOpen(int id) { 

    boolean qOpened = false; 

   

    try { 

        releaseCameraAndPreview(); 

        mCamera = Camera.open(id); 

        qOpened = (mCamera != null); 

    } catch (Exception e) { 

       Log.e(getString(R.string.app_name), "failed to open Camera"); 

        e.printStackTrace(); 

    } 

 

    return qOpened;     



 

private voidreleaseCameraAndPreview() { 

   mPreview.setCamera(null); 

    if (mCamera != null) { 

        mCamera.release(); 

        mCamera = null; 

    } 

}

 

(2)实现接口处理数据

创建一个类实现 SurfaceHolder.Callback  接口,用来处理Camera硬件的数据,显示可以使用SurfaceView。

class Preview extendsViewGroup implements SurfaceHolder.Callback { 

 

    SurfaceView mSurfaceView; 

    SurfaceHolder mHolder; 

 

    Preview(Context context) { 

       super(context); 

 

        mSurfaceView = new SurfaceView(context); 

        addView(mSurfaceView); 

 

        //Install a SurfaceHolder.Callback so we get notified when the 

        //underlying surface is created and destroyed. 

        mHolder = mSurfaceView.getHolder(); 

        mHolder.addCallback(this); 

        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 

    } 

... 

}

 

(3)设置和开启预览

public voidsetCamera(Camera camera) { 

    if (mCamera == camera) { return;} 

     

    stopPreviewAndFreeCamera(); 

     

    mCamera =camera; 

     

    if (mCamera != null) { 

       List<Size> localSizes =mCamera.getParameters().getSupportedPreviewSizes(); 

        mSupportedPreviewSizes = localSizes; 

        requestLayout(); 

       

        try{ 

            mCamera.setPreviewDisplay(mHolder); 

        }catch (IOException e) { 

            e.printStackTrace(); 

       } 

       

        //Important: Call startPreview() to start updating the preview 

        //surface. Preview must be started before you can take a picture. 

        mCamera.startPreview(); 

    } 

}

 

设置 Camera 参数

public voidsurfaceChanged(SurfaceHolder holder, int format, int w, int h) { 

    // Now that the size is known, setup the camera parameters and begin 

    // the preview. 

    Camera.Parameters parameters =mCamera.getParameters(); 

    parameters.setPreviewSize(mPreviewSize.width,mPreviewSize.height); 

   requestLayout(); 

    mCamera.setParameters(parameters); 

 

    // Important: Call startPreview() tostart updating the preview surface. 

    // Preview must be started beforeyou can take a picture. 

    mCamera.startPreview(); 

}

 

设置预览的屏幕方向 setCameraDisplayOrientation()

API 14 之前必须先停止预览,再旋转屏幕方向,最后重启预览

 

开启预览可以使用 Camera.takePicture()拍照,传入Camera.PictureCallback 和Camera.ShutterCallback 反馈操作结果。

 

拍完照之后要恢复预览,便于用户拍下一张照片

@Override 

public voidonClick(View v) { 

    switch(mPreviewState) { 

    case K_STATE_FROZEN: 

        mCamera.startPreview(); 

        mPreviewState = K_STATE_PREVIEW; 

       break; 

 

    default: 

        mCamera.takePicture( null, rawCallback, null); 

        mPreviewState = K_STATE_BUSY; 

    } // switch 

   shutterBtnConfig(); 

}

 

使用完记得销毁Camera 对象

public voidsurfaceDestroyed(SurfaceHolder holder) { 

    // Surface will be destroyed when wereturn, so stop the preview. 

    if (mCamera != null) { 

        //Call stopPreview() to stop updating the preview surface. 

        mCamera.stopPreview(); 

    } 



 

/** 

 * When this function returns, mCamera will be null. 

 */ 

private voidstopPreviewAndFreeCamera() { 

 

    if (mCamera != null) { 

        //Call stopPreview() to stop updating the preview surface. 

        mCamera.stopPreview(); 

     

        //Important: Call release() to release the camera for use by other 

        //applications. Applications should release the camera immediately 

        //during onPause() and re-open() it during onResume()). 

        mCamera.release(); 

     

        mCamera = null; 

    } 

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息