2013-04-17 22 views
17

Fotoğraf çekerken kendi kamera önizlemesini uygulayan bir kamera uygulaması oluşturuyorum. Uygulama şu anda dikey modda zorlanıyor.Fotoğraf makinesi önizlemesi, doğru boyutları ayarladıktan sonra bile gerilmiş

Sorunum, kameranın önizlemesinin biraz gerildiği (en boy oranı biraz kapalı). Komik olan şey, SurfaceView boyutunu her zaman önizleme boyutuna uyacak şekilde ayarlamamdır.

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; 
     } 
    } 
} 

onLayout genişliğinde lütfen unutmayın: Burada

benim kamera önizlemesini göstermek için kullanmak düzenidir ... Bu boy oranı daima perserved gerektiğini sağlamaktadır ... ama değil ve uygulama her zaman dikey olarak çalıştığı için yükseklik değiştirilir. Ben kodu debug ettik enter image description here

enter image description here

:

ben gibi sorun göründüğünü size göstermek için bazı resimler dahil ediyorum. Önizleme boyutu 1280x720 olarak ayarlanmıştır ve düzenin boyutu da bu boyuta uyacak şekilde doğru şekilde ayarlanmaktadır.

... Ben de farklı düzenler denedim ama sonuç hep aynıydı

cevap

5

ben, aynı sorunu yaşıyor bu bulmacanın bazı gün sonra, benim Java sınıfı bu kod üzerinde son:

Yani, kamera ekranı bir boyut (yükseklik x genişlik) 576x720 ve ekranım 1184x720 olduğu için sorun oluşuyordu. Yani, kamera önizleme (benim yüzey görünümü sınıfım) ebeveyni doldurmak için gerilmiş.

Bu nedenle, bu yaklaşım, bu görünümü ekranımdan daha büyük hale getirmek ve ekranımın alanını görüntülemek. Bu yüzden, bu garip çerçeve kombinasyonunu kullanmak zorundaydım (lineer yerleşimin içindeki göreceli bir düzen), böylece göreceli olmanın büyüklüğü istediğim kadar büyük olacak - yüzey görünümü onu dolduracak - ve lineer sadece görüntülemek istediğim bölüm.

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; 
     } 
    } 

} 
+0

denememiş mı

<ImageView android:id="@+id/imageView" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" /> 
tam olarak ama bu aslında işe yarıyor gibi görünüyor. Güzel. –

+0

Bu çözüm benim için çalışmadı. Lütfen http: // stackoverflow adlı soruma bakın.com/questions/21107208/nasıl-yapmak-yapmak-kamera-önizleme-boyutu-imageview-boyutu-önizleme-germek –

+1

getBestPreviewSize() her zaman bana kamera ve aynı sorun görünümü daha küçük boyutunda streç görüntü veriyor. –

1

Ben Kodun altında ... aynı sorunu çözmeye çalışıyorlar benim için çalıştı:

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); 
} 

Sen iplik görebilirsiniz: bir çözüm İşte Resizing surface view for aspect ratio change in video display in android

0

oluyor

surfaceChanged sadece en iyi önizleme boyutunu elde etmek için

@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); 
    } 

Bu imageReview çekilen görüntüyü ayarlamak, ancak

Eğer gerilmiş görüntü sorunu için imageview scaleType niteliğini ayarlamanız gerekir bitmap dönüşünü almak için bir yöntem gerekir

İlgili konular