如何使用框架布局拍摄照片?

Posted

技术标签:

【中文标题】如何使用框架布局拍摄照片?【英文标题】:How to capture photo using frame layout? 【发布时间】:2017-11-24 08:19:29 【问题描述】:

在我的项目中,我尝试在 framelayout 中显示相机。它显示完美,但我想在按下按钮时捕捉图像。我在下面附上了我的代码。

这是我的 MainActivity.java 代码:

public class MainActivity extends AppCompatActivity 

@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    getFragmentManager().beginTransaction().add(R.id.cameraview1, new CameraExtractionFragment()).commit();

    Button but = (Button)findViewById(R.id.selfienext);
    but.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View v) 
            Intent intent = new Intent(MainActivity.this,DocumentCapture.class);
            startActivity(intent);
        
    );


CameraExtractionFragment.java 代码:

class CameraExtractionFragment extends Fragment 
private CameraExtraction mCameraExtraction;
Camera mCamera;
int mNumberOfCameras;
int cameraId;
int rotation;

@Override
public void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);

    mCameraExtraction = new CameraExtraction(
            this.getActivity().getBaseContext(),
            this.getActivity().getWindowManager().getDefaultDisplay().getRotation()
    );

    // Find the total number of cameras available
    mNumberOfCameras = Camera.getNumberOfCameras();

    // Find the ID of the rear-facing ("default") camera
    Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
    for (int i = 0; i < mNumberOfCameras; i++) 
        Camera.getCameraInfo(i, cameraInfo);
        if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) 
            cameraId = i;
        
    


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)               
    return mCameraExtraction;


@Override
public void onResume() 
    super.onResume();

    // Use mCurrentCamera to select the camera desired to safely restore
    // the fragment after the camera has been changed
    mCamera = Camera.open(cameraId);
    mCameraExtraction.setCamera(mCamera);


@Override
public void onPause() 
    super.onPause();

    if (mCamera != null)
    
        mCamera.stopPreview();
        mCamera.release();
    



// Modo en el que se pinta la cámara: encajada por dentro o saliendo los bordes por fuera.
public enum CameraViewMode 

    /**
     * Inner mode
     */
    Inner,
    /**
     * Outer mode
     */
    Outer


CameraExtraction.java 代码:

class CameraExtraction extends ViewGroup implements SurfaceHolder.Callback 

private final String TAG = "CameraExtraction";

Camera mCamera;
SurfaceHolder mHolder;
SurfaceView mSurfaceView;
int mNumberOfCameras;
int cameraId;
Rect desiredSize;
CameraExtractionFragment.CameraViewMode cameraViewMode;
boolean mSurfaceCreated = false;
List<Camera.Size> mSupportedPreviewSizes;
int rotation;
Camera.Size mPreviewSize;

public CameraExtraction(Context context, int rotation) 
    super(context);

    this.rotation = rotation;

    mSurfaceView = new SurfaceView(context);

    addView(mSurfaceView);

    // Install a SurfaceHolder.Callback so we get notified when the
    mHolder = mSurfaceView.getHolder();
    mHolder.addCallback(this);
    mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

    cameraViewMode = CameraExtractionFragment.CameraViewMode.Inner;


public void setCamera(Camera camera) 
    mCamera = camera;
    if (mCamera != null) 
        mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
        if (mSurfaceCreated) requestLayout();
    


public void switchCamera(Camera camera) 
    setCamera(camera);
    try 
        camera.setPreviewDisplay(mHolder);
     catch (IOException exception) 
        Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
    


@SuppressLint("DrawAllocation")
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
    if (mSurfaceView == null ||mSurfaceView.getHolder() == null) return;

    if (mSurfaceView.getHolder().getSurface() == null) 
        // preview surface does not exist
        return;
    

    final int width = resolveSize(getSuggestedMinimumWidth(),
            widthMeasureSpec);
    final int height = resolveSize(getSuggestedMinimumHeight(),
            heightMeasureSpec);
    setMeasuredDimension(width, height);

    if (mSupportedPreviewSizes != null) 

        mPreviewSize = getNearestPreviewSize(mCamera.new Size(widthMeasureSpec,heightMeasureSpec));
    

    if (mCamera != null) 
        Camera.Parameters parameters = mCamera.getParameters();
        parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);

        mCamera.setParameters(parameters);
    


@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) 
    if (getChildCount() > 0) 
        final View child = getChildAt(0);

        final int width = r - l;
        final int height = b - t;

        int previewWidth = width;
        int previewHeight = height;
        if (mPreviewSize != null) 
            previewWidth = mPreviewSize.width;
            previewHeight = mPreviewSize.height;
        

        // Center the child SurfaceView within the parent.
        if (width * previewHeight > height * previewWidth) 
            final int scaledChildWidth = previewWidth * height
                    / previewHeight;
            child.layout((width - scaledChildWidth) / 2, 0,
                    (width + scaledChildWidth) / 2, height);
         else 
            final int scaledChildHeight = previewHeight * width
                    / previewWidth;
            child.layout(0, (height - scaledChildHeight) / 2, width,
                    (height + scaledChildHeight) / 2);
        
    


@Override
public void surfaceCreated(SurfaceHolder holder) 
    try 
        if (mCamera != null) 
            mCamera.setPreviewDisplay(holder);
            mCamera.setPreviewCallback(new Camera.PreviewCallback() 
                @Override
                public void onPreviewFrame(byte[] data, Camera camera) 
                
            );
        
     catch (IOException exception) 
        Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
    


@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) 
    if (mSurfaceView == null || mSurfaceView.getHolder() == null) return;

    if (mSurfaceView.getHolder().getSurface() == null) 
        // preview surface does not exist
        return;
    

    // set preview size and make any resize, rotate or
    // reformatting changes here
    Camera.Parameters param = mCamera.getParameters();
    Point previewSize = new Point(480,480);

    Camera.Size size = getNearestPreviewSize(mCamera.new Size(previewSize.x,previewSize.y));
    param.setPreviewSize(size.width, size.height);
    mCamera.setParameters(param);
    rotation = setCameraDisplayOrientation(cameraId, mCamera);

    // start preview with new settings
    try 
        mCamera.setPreviewCallback(new Camera.PreviewCallback() 

            @Override
            public void onPreviewFrame(byte[] data, Camera camera) 
                // TODO Auto-generated method stub

            
        );
        mCamera.setPreviewDisplay(mSurfaceView.getHolder());
        mCamera.startPreview();

     catch (Exception e) 
        Log.d("androidControlSurfaceView",
                "Error starting camera preview: " + e.getMessage());
    


@Override
public void surfaceDestroyed(SurfaceHolder holder) 
    if (mCamera != null)
    
//          mCamera.stopPreview();
//          mCamera.release();
    



protected Rect getCameraViewSizeCompensated(Camera.Size cameraPreviewSize, Point hostViewSize) 
    Rect toReturn=null;

    float ratioWidth = hostViewSize.x / (float)cameraPreviewSize.width;
    float ratioHeight = hostViewSize.y / (float)cameraPreviewSize.height;

    switch (cameraViewMode)
        case Inner:
            if (ratioWidth < ratioHeight) 
                int newHeight = (int)(cameraPreviewSize.height*ratioWidth);
                int y = (hostViewSize.y - newHeight) / 2;
                toReturn = new Rect(0, y, hostViewSize.x, y+newHeight);
             else 
                int newWidth = (int)(cameraPreviewSize.width*ratioHeight);
                int x = (hostViewSize.x - newWidth) / 2;
                toReturn = new Rect(x, 0, x+newWidth,hostViewSize.y);
            
            break;
        case Outer:
            if (ratioWidth < ratioHeight) 
                int newWidth = (int)(cameraPreviewSize.width*ratioHeight);
                int x = (hostViewSize.x - newWidth) / 2;
                toReturn = new Rect(x, 0, x+newWidth,hostViewSize.y);
             else 
                int newHeight = (int)(cameraPreviewSize.height*ratioWidth);
                int y = (hostViewSize.y - newHeight) / 2;
                toReturn = new Rect(0, y, hostViewSize.x, y+newHeight);
            
            break;
    
    return toReturn;


private Camera.Size getNearestPreviewSize(Camera.Size size) 
    List<Camera.Size> availableSizes =  
mCamera.getParameters().getSupportedPreviewSizes();
    if (availableSizes == null || availableSizes.size() <= 0) return null;

    Camera.Size toReturn = availableSizes.get(0);
    int distance = Math.abs(size.width*size.height - toReturn.width*toReturn.height);
    for (int a=1; a<availableSizes.size(); a++) 
        int temp = Math.abs(size.width*size.height - availableSizes.get(a).width*availableSizes.get(a).height);
        if (temp < distance) 
            distance = temp;
            toReturn = availableSizes.get(a);
        
    
    return toReturn;



public int setCameraDisplayOrientation(int cameraId, android.hardware.Camera camera) 

    Camera.CameraInfo info = new Camera.CameraInfo();
    Camera.getCameraInfo(cameraId, info);
    int degrees = 0;

    switch (rotation) 
        case Surface.ROTATION_0: degrees = 0; break;
        case Surface.ROTATION_90: degrees = 90; break;
        case Surface.ROTATION_180: degrees = 180; break;
        case Surface.ROTATION_270: degrees = 270; break;
    

    int result;
    if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) 
        result = (info.orientation + degrees) % 360;
        result = (360 - result) % 360;  // compensate the mirror
     else   // back-facing
        result = (info.orientation - degrees + 360) % 360;
    
    camera.setDisplayOrientation(result);
    return result/90;


DocumentCapture.java 代码:

 public class DocumentCapture extends AppCompatActivity 

@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_document_capture);

    Button but = (Button)findViewById(R.id.docnext);
    but.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View v) 
            Intent intent = new Intent(DocumentCapture.this,VerificationResult.class);
            startActivity(intent);
        
    );



这是我的捕获按钮代码:

<LinearLayout
    android:layout_
    android:layout_
    android:orientation="horizontal"
    android:layout_marginTop="5dp">
         <FrameLayout
             android:id="@+id/cameraview1"
             android:layout_
             android:layout_>
         </FrameLayout>

        <Button
            android:id="@+id/selfiecapture"
            android:layout_
            android:layout_
            android:layout_marginLeft="10dp"
            android:background="@drawable/btn"
            android:text="Capture"
            android:textColor="#FFFFFF"
            android:textSize="17dp"
            android:textAllCaps="false"
            android:layout_gravity="left"/>           

</LinearLayout>

【问题讨论】:

你看过***.com/questions/10913682/…吗? Intent intent = new Intent(MainActivity.this,DocumentCapture.class); 你提到`DocumentCapture.class`在你的帖子中添加这个类 【参考方案1】:

打通google官方页面Link后

您可以使用该方法调用Camera API。

CameraActivity

public class CameraActivity extends Activity 

private Camera mCamera;
private CameraPreview mPreview;

@Override
public void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    // Create an instance of Camera
    mCamera = getCameraInstance();

    // Create our Preview view and set it as the content of our activity.
    mPreview = new CameraPreview(this, mCamera);
    FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
    preview.addView(mPreview);
    // Add a listener to the Capture button
    Button captureButton = (Button) findViewById(id.button_capture);
    captureButton.setOnClickListener(
    new View.OnClickListener() 
    @Override
    public void onClick(View v) 
        // get an image from the camera
        mCamera.takePicture(null, null, mPicture);
    
   
  );
    


 /** A safe way to get an instance of the Camera object. */
 public static Camera getCameraInstance()
    Camera c = null;
    try 
    c = Camera.open(); // attempt to get a Camera instance
    
    catch (Exception e)
    // Camera is not available (in use or does not exist)
    
    return c; // returns null if camera is unavailable


private PictureCallback mPicture = new PictureCallback() 

@Override
public void onPictureTaken(byte[] data, Camera camera) 

    File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
    if (pictureFile == null)
        Log.d(TAG, "Error creating media file, check storage permissions: " +
            e.getMessage());
        return;
    

    try 
        FileOutputStream fos = new FileOutputStream(pictureFile);
        fos.write(data);
        fos.close();
     catch (FileNotFoundException e) 
        Log.d(TAG, "File not found: " + e.getMessage());
     catch (IOException e) 
        Log.d(TAG, "Error accessing file: " + e.getMessage());
    
  
;

创建相机预览类

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback 
     private SurfaceHolder mHolder;
     private Camera mCamera;

public CameraPreview(Context context, Camera camera) 
    super(context);
    mCamera = camera;

    // Install a SurfaceHolder.Callback so we get notified when the
    // underlying surface is created and destroyed.
    mHolder = getHolder();
    mHolder.addCallback(this);
    // deprecated setting, but required on Android versions prior to 3.0
    mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);


public void surfaceCreated(SurfaceHolder holder) 
    // The Surface has been created, now tell the camera where to draw the preview.
    try 
        mCamera.setPreviewDisplay(holder);
        mCamera.startPreview();
     catch (IOException e) 
        Log.d(TAG, "Error setting camera preview: " + e.getMessage());
    


public void surfaceDestroyed(SurfaceHolder holder) 
    // empty. Take care of releasing the Camera preview in your activity.


public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) 
    // If your preview can change or rotate, take care of those events here.
    // Make sure to stop the preview before resizing or reformatting it.

    if (mHolder.getSurface() == null)
      // preview surface does not exist
      return;
    

    // stop preview before making changes
    try 
        mCamera.stopPreview();
     catch (Exception e)
      // ignore: tried to stop a non-existent preview
    

    // set preview size and make any resize, rotate or
    // reformatting changes here

    // start preview with new settings
    try 
        mCamera.setPreviewDisplay(mHolder);
        mCamera.startPreview();

     catch (Exception e)
        Log.d(TAG, "Error starting camera preview: " + e.getMessage());
    


将这些添加到您的 androidmanifest.xml 文件中

 <uses-feature android:name="android.hardware.camera" />
 <uses-permission android:name="android.permission.CAMERA" />
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

【讨论】:

以上是关于如何使用框架布局拍摄照片?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Anywall 在 Parse 上拍摄和保存照片? [关闭]

如何在 iOS8.1 上使用 Swift 按顺序拍摄多张照片(每张延迟 1 秒)?

如何获取拍摄照片的创建日期?

如何使用Android中的Camera2 API在不预览的情况下拍摄多张照片?

怎么使用全景拍摄?

如何在 iphone 中使用 avFoundation 像 Instagram 应用一样拍摄方形照片?