2013-07-23 13 views
14

Ich habe eine Kamera-App basierend auf Tutorial erstellt. Die von mir verwendete Vorschauklasse stammt von api-Demos "CameraPreview". Ich habe eine Änderung von here hinzugefügt (Vorschau wurde immer um 90 ° gedreht). So stelle ich die Vorschaugröße ein:android kamera Vorschau falsches Seitenverhältnis

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { 
    // Now that the size is known, set up the camera parameters and begin 
    // the preview. 
    Camera.Parameters parameters = mCamera.getParameters(); 
    Display display = ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); 

    if (display.getRotation() == Surface.ROTATION_0) { 
     parameters.setPreviewSize(mPreviewSize.height, mPreviewSize.width); 
     mCamera.setDisplayOrientation(90); 
    } 

    if (display.getRotation() == Surface.ROTATION_90) { 
     parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); 
    } 

    if (display.getRotation() == Surface.ROTATION_180) { 
     parameters.setPreviewSize(mPreviewSize.height, mPreviewSize.width); 
    } 

    if (display.getRotation() == Surface.ROTATION_270) { 
     parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); 
     mCamera.setDisplayOrientation(180); 
    } 
    parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); 

    requestLayout(); 

    mCamera.setParameters(parameters); 
    mCamera.startPreview(); 
} 

Aber die Vorschau wird mit falschem Seitenverhältnis angezeigt. Ist es, weil der Code oben oder wahrscheinlich wegen des Layouts i ?: verwenden

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:layout_width="match_parent" 
android:layout_height="match_parent" > 

<Button 
    android:id="@+id/button_capture" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:layout_alignParentBottom="true" 
    android:text="@string/capture" /> 

<FrameLayout 
    android:id="@+id/camera_preview" 
    android:layout_width="100dp" 
    android:layout_height="match_parent"/> 

So wie das richtige Seitenverhältnis zu bekommen? Danke im Voraus.

P.S. Ich lese die Antwort von: Android camera preview look strange Aber das funktioniert nicht für mich.

+0

vielleicht haben Sie diese schließen könnte Problem ? – Poutrathor

+0

warum? was hat sich geändert? – dermoritz

+1

Zuerst müssen Sie nicht glauben, 2. Ich habe keine Zeit, die anderen Lösungen zu versuchen (ein Jahr nach dem Posten der Frage). Sobald ich die anderen Antworten versucht habe, werde ich Feedback geben. Bis dahin ist alles in Ordnung ... – dermoritz

Antwort

21

Probieren Sie die Vorschau Größen zu ändern mit dem Hinzufügen dieser Funktion:

private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) { 
    final double ASPECT_TOLERANCE = 0.05; 
    double targetRatio = (double) w/h; 

    if (sizes==null) return null; 

    Camera.Size optimalSize = null; 

    double minDiff = Double.MAX_VALUE; 

    int targetHeight = h; 

    // Find size 
    for (Camera.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); 
     } 
    } 

    if (optimalSize == null) { 
     minDiff = Double.MAX_VALUE; 
     for (Camera.Size size : sizes) { 
      if (Math.abs(size.height - targetHeight) < minDiff) { 
       optimalSize = size; 
       minDiff = Math.abs(size.height - targetHeight); 
      } 
     } 
    } 
    return optimalSize; 
} 

Und die Größen aus diesen optimierten Werte einstellen:

List<Camera.Size> sizes = parameters.getSupportedPreviewSizes(); 
Camera.Size optimalSize = getOptimalPreviewSize(sizes, getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels); 

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

Ich hoffe, das funktioniert :)

Mit freundlichen Grüßen

Henric

+0

wie ich in meiner Frage angegeben habe, verwende ich diesen Code (es ist von Api-Demos "CameraPreview"). Ich denke, das Problem hängt von meinem Layout und davon ab, wie ich die Vorschau hinzufüge. – dermoritz

+0

Diese Antwort ist sehr nützlich, sollte akzeptiert werden. – zionpi

+0

@dermoritz Es ist kein Layout-Problem! Sie müssen die Parameter eines der 'mCamera'-Objekte eine Zeile über' mCamera.startPreview() 'in der' CameraPreivew.java'-Klasse setzen. Funktioniert bei mir. Diese Antwort sollte akzeptiert werden! – 000000000000000000000

3

Der folgende Code ändert die Breite/Höhe des Kameravorschaucontainers so, dass er dem Seitenverhältnis der Kameravorschau entspricht.

1

Verwenden Sie die obige Lösung mit der Methode private Size getOptimalPreviewSize (List Größen, int w, int h). hat gut funktioniert! Ich hatte Probleme mit dem Seitenverhältnis im Hochformat: Hier ist meine Lösung mit. Mischen mit android Dokumentation:

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 
      Camera.Parameters params = mCamera.getParameters(); 
      params.set("orientation", "portrait"); 
      Size optimalSize=getOptimalPreviewSize(params.getSupportedPreviewSizes(), getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels); 
      params.setPreviewSize(optimalSize.width, optimalSize.height); 
      mCamera.setParameters(params); 
      // start preview with new settings 
      try { 

       mCamera.setPreviewDisplay(mHolder); 
       mCamera.startPreview(); 

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

Henric Antwort für mich funktionierte nicht, also habe ich eine andere Methode geschaffen, die die optimale Vorschaugröße für jede Kamera die Zielansicht aktuelle Breite und Höhe und auch die Aktivität gegeben bestimmt Orientierung:

public static Size getOptimalPreviewSize(List<Camera.Size> cameraPreviewSizes, int targetWidth, int targetHeight, boolean isActivityPortrait) { 
    if (CommonUtils.isEmpty(cameraPreviewSizes)) { 
     return null; 
    } 

    int optimalHeight = Integer.MIN_VALUE; 
    int optimalWidth = Integer.MIN_VALUE; 

    for (Camera.Size cameraPreviewSize : cameraPreviewSizes) { 
     boolean isCameraPreviewHeightBigger = cameraPreviewSize.height > cameraPreviewSize.width; 
     int actualCameraWidth = cameraPreviewSize.width; 
     int actualCameraHeight = cameraPreviewSize.height; 

     if (isActivityPortrait) { 
      if (!isCameraPreviewHeightBigger) { 
       int temp = cameraPreviewSize.width; 
       actualCameraWidth = cameraPreviewSize.height; 
       actualCameraHeight = temp; 
      } 
     } else { 
      if (isCameraPreviewHeightBigger) { 
       int temp = cameraPreviewSize.width; 
       actualCameraWidth = cameraPreviewSize.height; 
       actualCameraHeight = temp; 
      } 
     } 

     if (actualCameraWidth > targetWidth || actualCameraHeight > targetHeight) { 
      // finds only smaller preview sizes than target size 
      continue; 
     } 

     if (actualCameraWidth > optimalWidth && actualCameraHeight > optimalHeight) { 
      // finds only better sizes 
      optimalWidth = actualCameraWidth; 
      optimalHeight = actualCameraHeight; 
     } 
    } 

    Size optimalSize = null; 

    if (optimalHeight != Integer.MIN_VALUE && optimalWidth != Integer.MIN_VALUE) { 
     optimalSize = new Size(optimalWidth, optimalHeight); 
    } 

    return optimalSize; 
} 

Diese verwendet ein Objekt individuelle Größe, weil Android Size nach API 21.

public class Size { 

    private int width; 
    private int height; 

    public Size(int width, int height) { 
     this.width = width; 
     this.height = height; 
    } 

    public int getHeight() { 
     return height; 
    } 

    public int getWidth() { 
     return width; 
    } 

} 

Sie können zur Verfügung davon abhalten mine die Breite und Höhe einer Ansicht, indem Sie auf ihre globalen Layoutänderungen achten und dann die neuen Dimensionen festlegen können. Dies zeigt auch, wie die Aktivitätsausrichtung programmgesteuert zu bestimmen:

cameraPreviewLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { 
      @Override 
      public void onGlobalLayout() { 
       // gets called after layout has been done but before display. 
       cameraPreviewLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this); 

       boolean isActivityPortrait = getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT; 
       Size optimalCameraPreviewSize = CustomUtils.getOptimalPreviewSize(cameraPreview.getCameraSizes(), cameraPreviewLayout.getWidth(), cameraPreviewLayout.getHeight(), isActivityPortrait); 
       if (optimalCameraPreviewSize != null) { 
        LinearLayout.LayoutParams cameraPreviewLayoutParams = new LinearLayout.LayoutParams(optimalCameraPreviewSize.getWidth(), optimalCameraPreviewSize.getHeight()); 
        cameraPreviewLayout.setLayoutParams(cameraPreviewLayoutParams); 
       } 
      } 
     }); 
2

Problem ist wirklich in der Art und Weise Sie Layout-Dinge. dort ist onLayout in Preview Klasse überschrieben. Idee seiner Arbeit ist, Kind SurfaceView Größe nach gefundenen optimalen Size festzulegen.aber es dauert nicht Drehung berücksichtigt, so dass Sie es selbst tun müssen:

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

statt

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

Trick ist Breite und Höhe zu tauschen, die wegen 90-Grad-Drehung erfolgt erreicht durch

mCamera.setDisplayOrientation(90); 

Sie auch auf Orientierung je Kind Vorschau Größeneinstellung prüfen könnte gabeln, die Sie in

gesetzt
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { 
     //... 
    } 

(in von mir zur Verfügung gestellt Code ist es immer für 90-Grad-Drehung, für 180 müssen Sie nichts tun und wenn Sie keine Drehung einstellen, gibt es keine Notwendigkeit, Breite und Höhe zu tauschen)

Eine andere Sache, erwähnenswert - wenn getOptimalPreviewSize für Fall berechnet wird, wenn Sie Drehung und Sie tauschen Kind Breite und Höhe sollten Sie auch Eltern (Preview) Breite und Höhe in onMeasure getauscht passieren:

if (mSupportedPreviewSizes != null) { 
    //noinspection SuspiciousNameCombination 
    final int previewWidth = height; 
    //noinspection SuspiciousNameCombination 
    final int previewHeight = width; 
    mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, previewWidth, previewHeight); 
} 
Verwandte Themen