如何使用框架布局拍摄照片?
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 秒)?