studio permission open intent developer custom android android-camera surfaceview

open - permission camera android studio



Vista previa de la cámara estirada incluso después de configurar las dimensiones correctas (3)

Estoy creando una aplicación de cámara que implementa su propia vista previa de cámara para tomar fotografías. La aplicación está actualmente forzada en modo retrato.

Mi problema es que la vista previa de la cámara está ligeramente estirada (la relación de aspecto está un poco desactivada). Lo curioso es que estoy configurando el tamaño de mi SurfaceView para que siempre coincida con el tamaño de la vista previa. Esto asegura que la relación de aspecto siempre debe conservarse ... pero no es ...

Aquí está el diseño que uso para mostrar la vista previa de mi cámara:

public class Cp extends ViewGroup implements SurfaceHolder.Callback { private final String TAG = "CameraPreview"; private boolean mPreviewRunning = false; private SurfaceView mSurfaceView; private SurfaceHolder mHolder; private Size mPreviewSize; private List<Size> mSupportedPreviewSizes; private Camera mCamera; public boolean IsPreviewRunning() { return mPreviewRunning; } public Cp(Context context) { this(context, null, 0); } public Cp(Context context, AttributeSet attrs) { this(context, attrs, 0); } public Cp(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); 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); } public void setCamera(Camera camera) { mCamera = camera; if (mCamera != null) { requestLayout(); } } public void switchCamera(Camera camera) { setCamera(camera); try { camera.setPreviewDisplay(mHolder); } catch (IOException exception) { Log.e(TAG, "IOException caused by setPreviewDisplay()", exception); } Camera.Parameters parameters = camera.getParameters(); parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); requestLayout(); camera.setParameters(parameters); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // We purposely disregard child measurements because act as a wrapper to // a SurfaceView that // centers the camera preview instead of stretching it. final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec); final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec); setMeasuredDimension(width, height); if (mSupportedPreviewSizes == null && mCamera != null) { mSupportedPreviewSizes = mCamera.getParameters() .getSupportedPreviewSizes(); } if (mSupportedPreviewSizes != null) { mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height); } } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { if (changed && 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.height; previewHeight = mPreviewSize.width; } if (previewWidth == 0) { previewWidth = 1; } if (previewHeight == 0) { previewHeight = 1; } // 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) { // The Surface has been created, acquire the camera and tell it where to // draw. try { if (mCamera != null) { Parameters params = mCamera.getParameters(); mSupportedPreviewSizes = params.getSupportedPreviewSizes(); mCamera.setPreviewDisplay(holder); } } catch (IOException exception) { Log.e(TAG, "IOException caused by setPreviewDisplay()", exception); } } @Override public void surfaceDestroyed(SurfaceHolder holder) { // Surface will be destroyed when we return, so stop the preview. stop(); } private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) { final double ASPECT_TOLERANCE = 0.1; double targetRatio = (double) w / h; if (sizes == null) return null; Size optimalSize = null; double minDiff = Double.MAX_VALUE; int targetHeight = h; // Try to find an size match aspect ratio and size for (Size size : sizes) { double ratio = (double) size.width / size.height; if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue; if (Math.abs(size.height - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - targetHeight); } } // Cannot find the one match the aspect ratio, ignore the requirement if (optimalSize == null) { minDiff = Double.MAX_VALUE; for (Size size : sizes) { if (Math.abs(size.height - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - targetHeight); } } } return optimalSize; } @Override public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { if (mCamera != null) { // Now that the size is known, set up the camera parameters and // begin the preview. Camera.Parameters parameters = mCamera.getParameters(); if (mPreviewSize != null) { parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); } requestLayout(); mCamera.setParameters(parameters); mCamera.startPreview(); mPreviewRunning = true; } } public void stop() { if (mCamera != null) { mCamera.stopPreview(); mPreviewRunning = false; mCamera = null; } } }

Tenga en cuenta que en onLayout se intercambian el ancho y la altura porque la aplicación siempre se ejecuta en vertical.

Incluyo algunas fotos para mostrarles cómo se ve el problema:

He depurado el código. El tamaño de la vista previa se está estableciendo en 1280x720 y el tamaño del diseño también se está ajustando correctamente para que coincida con ese tamaño.

También he intentado diferentes diseños pero el resultado fue siempre el mismo ...


Aquí hay una solución

surfaceChanged es solo para obtener el mejor tamaño de vista previa

@Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { Log.e("MYTAG", "surfaceChanged " ); Camera.Parameters myParameters = camera.getParameters(); Camera.Size myBestSize = getBestPreviewSize(width, height, myParameters); if(myBestSize != null){ myParameters.setPreviewSize(myBestSize.width, myBestSize.height); camera.setParameters(myParameters); camera.startPreview(); } } @Override public void onPictureTaken(byte[] data, Camera camera) { Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); imageReview.setImageBitmap(bitmap); }

Esto establecerá la imagen capturada en imageReview, pero necesita un método para obtener la rotación del mapa de bits

necesita establecer el atributo de tipo de vista de escala de visualización para el problema de imagen estirada

<ImageView android:id="@+id/imageView" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" />


Estaba teniendo el mismo problema, después de algunos días en este rompecabezas, mi clase de Java terminó con este código:

Entonces, el problema estaba ocurriendo porque la pantalla de la cámara tenía un tamaño (alto x ancho) 576x720, y mi pantalla era 1184x720. Por lo tanto, la vista previa de la cámara (mi clase de vista de superficie) se extendió para completar el padre.

Entonces, el enfoque que funcionó es hacer que esta vista sea más grande que mi pantalla, y que solo muestre el área de mi pantalla. Por lo tanto, tuve que usar esta combinación de cuadros extraños (un diseño relativo dentro de una distribución lineal), de modo que el tamaño del relativo sea tan grande como quiera (la vista de la superficie se rellene), y la lineal tomará solo el parte que quiero mostrar.

package com.example.frame.camera; import android.content.Context; import android.hardware.Camera; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.ViewGroup.LayoutParams; import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.Toast; import com.example.frame.MainActivity; public class NativeCamera extends SurfaceView implements SurfaceHolder.Callback { static private NativeCamera instance; private LinearLayout frame = null; private RelativeLayout innerFrame = null; private Camera camera; private final SurfaceHolder previewHolder; private static final String TAG = "NativeCamera.java"; private boolean inPreview = false; private boolean cameraConfigured = false; private boolean frontCamera = false; private Camera.Size size; static public NativeCamera getInstance() { if (NativeCamera.instance == null) { if (MainActivity.debug) { Log.d(TAG, "Creating Camera Singleton"); } NativeCamera.instance = new NativeCamera(MainActivity.instance); } return NativeCamera.instance; } public void onResume() { if (MainActivity.debug) { Log.d(TAG, "onResume"); } camera = Camera.open(); if (size != null) { initPreview(size.width, size.height); } startPreview(); } public void onPause() { if (MainActivity.debug) { Log.d(TAG, "onPause"); } if (inPreview) { camera.stopPreview(); } camera.release(); camera = null; inPreview = false; } public void onDestroy() { if (MainActivity.debug) { Log.d(TAG, "onDestroy"); } NativeCamera.instance = null; } public void onSwitch() { frontCamera = !frontCamera; if (inPreview) { camera.stopPreview(); } camera.release(); int cam = frontCamera ? 1 : 0; camera = Camera.open(cam); if (size != null) { initPreview(size.width, size.height); } startPreview(); } private NativeCamera(Context context) { super(context); // TODO Auto-generated constructor stub // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed. previewHolder = getHolder(); previewHolder.addCallback(this); // deprecated setting, but required on Android versions prior to 3.0 // previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); innerFrame = new RelativeLayout(MainActivity.instance); innerFrame.addView(this); frame = new LinearLayout(MainActivity.instance); frame.addView(innerFrame); } public LinearLayout getFrame() { return frame; } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // TODO Auto-generated method stub if (MainActivity.debug) { Log.d(TAG, "surfaceChanged"); } initPreview(width, height); startPreview(); } public void surfaceCreated(SurfaceHolder holder) { // TODO Auto-generated method stub // no-op -- wait until surfaceChanged() } public void surfaceDestroyed(SurfaceHolder holder) { // TODO Auto-generated method stub // no-op } private Camera.Size getBestPreviewSize(int width, int height, Camera.Parameters parameters) { Camera.Size result = null; for (Camera.Size size : parameters.getSupportedPreviewSizes()) { if (size.width <= width && size.height <= height) { if (result == null) { result = size; } else { int resultArea = result.width * result.height; int newArea = size.width * size.height; if (newArea > resultArea) { result = size; } } } } this.size = result; return (result); } private void initPreview(int width, int height) { if (camera != null && previewHolder.getSurface() != null) { if (!cameraConfigured) { Camera.Parameters parameters = camera.getParameters(); Camera.Size size = getBestPreviewSize(width, height, parameters); if (size != null) { parameters.setPreviewSize(size.width, size.height); camera.setParameters(parameters); cameraConfigured = true; // Setting up correctly the view double ratio = size.height / (double) size.width; LayoutParams params = innerFrame.getLayoutParams(); params.height = MainActivity.size.y; params.width = (int) (MainActivity.size.y * ratio); innerFrame.setLayoutParams(params); int deslocationX = (int) (params.width / 2.0 - MainActivity.size.x / 2.0); innerFrame.animate().translationX(-deslocationX); } } try { camera.setPreviewDisplay(previewHolder); camera.setDisplayOrientation(90); } catch (Throwable t) { Log.e(TAG, "Exception in setPreviewDisplay()", t); Toast.makeText(MainActivity.instance, t.getMessage(), Toast.LENGTH_LONG).show(); } } } private void startPreview() { if (MainActivity.debug) { Log.d(TAG, "startPreview"); } if (cameraConfigured && camera != null) { camera.startPreview(); inPreview = true; } } }


He estado tratando de resolver el mismo problema ... A continuación, el código funcionó para mí:

private void setMyPreviewSize(int width, int height) { // Get the set dimensions float newProportion = (float) width / (float) height; // Get the width of the screen int screenWidth = getWindowManager().getDefaultDisplay().getWidth(); int screenHeight = getWindowManager().getDefaultDisplay().getHeight(); float screenProportion = (float) screenWidth / (float) screenHeight; // Get the SurfaceView layout parameters android.view.ViewGroup.LayoutParams lp = surfaceView.getLayoutParams(); if (newProportion > screenProportion) { lp.width = screenWidth; lp.height = (int) ((float) screenWidth / newProportion ); } else { lp.width = (int) (newProportion * (float) screenHeight); lp.height = screenHeight; } // Commit the layout parameters surfaceView.setLayoutParams(lp); }

Puede ver el hilo: Cambiar el tamaño de la vista de superficie para cambiar la relación de aspecto en la pantalla de video en Android