Camera 基礎

參數設置

Camera.Parameters param = camera.getParameters();
param.setPreviewSize(width, height);java

width通常大於height,默認攝像頭是橫向,預覽時須要設置camera.setDisplayOrientation(90);android

預覽大小

常見的分辨率爲4:3,或者16:9,即640x480和1280x720git

Android6.0的源代碼中,預覽的大小和PictureSize有關,先看看系統如何設置Picture Sizegithub

PictureSize設置

代碼位置app

public static void initialCameraPictureSize(
            Context context, Parameters parameters) {
        // When launching the camera app first time, we will set the picture
        // size to the first one in the list defined in "arrays.xml" and is also
        // supported by the driver.
        List<Size> supported = parameters.getSupportedPictureSizes();
        if (supported == null) return;
        for (String candidate : context.getResources().getStringArray(
                R.array.pref_camera_picturesize_entryvalues)) {
            if (setCameraPictureSize(candidate, supported, parameters)) {
                SharedPreferences.Editor editor = ComboPreferences
                        .get(context).edit();
                editor.putString(KEY_PICTURE_SIZE, candidate);
                editor.apply();
                return;
            }
        }
        Log.e(TAG, "No supported picture size found");
    }

讀取預先pref_camera_picturesize_entryvalues配置大小,而後在和設備支持的尺寸匹配,兩個相同的做爲pictureSize;並保存。ui

R.array.pref_camera_picturesize_entryvalues 中值爲this

<!-- When launching the camera app first time, we will set the picture
         size to the first one in the list that is also supported by the
         driver -->
    <string-array name="pref_camera_picturesize_entryvalues" translatable="false">
        <item>3264x2448</item>
        <item>2592x1944</item>
        <item>2592x1936</item>
        <item>2560x1920</item>
        <item>2048x1536</item>
        <item>1600x1200</item>
        <item>1280x960</item>
        <item>1024x768</item>
        <item>640x480</item>
        <item>320x240</item>
    </string-array>

setCameraPictureSize 方法比較預先設置的之中是否有設置支持的大小相等的值google

public static boolean setCameraPictureSize(
            String candidate, List<Size> supported, Parameters parameters) {
        int index = candidate.indexOf('x');
        if (index == NOT_FOUND) return false;
        int width = Integer.parseInt(candidate.substring(0, index));
        int height = Integer.parseInt(candidate.substring(index + 1));
        for (Size size : supported) {
            if (size.width == width && size.height == height) {
                parameters.setPictureSize(width, height);
                return true;
            }
        }
        return false;
    }

預覽大小設置

系統Camera設置

系統相機預覽大小的設置和picturesize有關。code

在startPreview中會調用updateCameraParametersPreference()方法orm

// Set the preview frame aspect ratio according to the picture size.
        Size size = mParameters.getPictureSize();

        mPreviewPanel = findViewById(R.id.frame_layout);
        mPreviewFrameLayout = (PreviewFrameLayout) findViewById(R.id.frame);
        mPreviewFrameLayout.setAspectRatio((double) size.width / size.height);

        // Set a preview size that is closest to the viewfinder height and has
        // the right aspect ratio.
        List<Size> sizes = mParameters.getSupportedPreviewSizes();
        Size optimalSize = Util.getOptimalPreviewSize(this,
                sizes, (double) size.width / size.height);
        Size original = mParameters.getPreviewSize();
        if (!original.equals(optimalSize)) {
            mParameters.setPreviewSize(optimalSize.width, optimalSize.height);

            // Zoom related settings will be changed for different preview
            // sizes, so set and read the parameters to get lastest values
            mCameraDevice.setParameters(mParameters);
            mParameters = mCameraDevice.getParameters();
        }

調用Util.getOptimalPreviewSize()方法獲取合適previewSize,

public static Size getOptimalPreviewSize(Activity currentActivity,
            List<Size> sizes, double targetRatio) {
        // Use a very small tolerance because we want an exact match.
        final double ASPECT_TOLERANCE = 0.001;
        if (sizes == null) return null;

        Size optimalSize = null;
        double minDiff = Double.MAX_VALUE;

        // Because of bugs of overlay and layout, we sometimes will try to
        // layout the viewfinder in the portrait orientation and thus get the
        // wrong size of preview surface. When we change the preview size, the
        // new overlay will be created before the old one closed, which causes
        // an exception. For now, just get the screen size.
        //獲取屏幕大小
        Point point = getDefaultDisplaySize(currentActivity, new Point());
        //相機默認橫屏,高度是二者中最小的一個
        int targetHeight = Math.min(point.x, point.y);
        // Try to find an size match aspect ratio and size
        for (Size size : sizes) {
            double ratio = (double) size.width / size.height;
            //相機支持的比率和targetRatio相差太大時,繼續查找
            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. This should not happen.
        // Ignore the requirement.
        if (optimalSize == null) {
            Log.w(TAG, "No preview size match the aspect ratio");
            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;
    }

根據targetRatio,和實際屏幕大小來選擇SupportedPreviewSizes中合適的值。targetRatio我以爲也能夠使用屏幕比例。

Zing中previewSize設置

代碼位置

initFromCameraParameters()方法會調用findBestPreviewSizeValue()方法獲取適合的大小;screenResolution爲屏幕大小

//private static final int MIN_PREVIEW_PIXELS = 320 * 240; // small screen
  //private static final int MAX_PREVIEW_PIXELS = 800 * 480; // large/HD screen
  private static Point findBestPreviewSizeValue(Camera.Parameters parameters,
                                                Point screenResolution,
                                                boolean portrait) {
    Point bestSize = null;
    int diff = Integer.MAX_VALUE;
    for (Camera.Size supportedPreviewSize : parameters.getSupportedPreviewSizes()) {
      int pixels = supportedPreviewSize.height * supportedPreviewSize.width;
      //預先設置大小
      if (pixels < MIN_PREVIEW_PIXELS || pixels > MAX_PREVIEW_PIXELS) {
        continue;
      }
      int supportedWidth = portrait ? supportedPreviewSize.height : supportedPreviewSize.width;
      int supportedHeight = portrait ? supportedPreviewSize.width : supportedPreviewSize.height;
      //不太理解爲啥要交叉相乘,總之是比較差值
      int newDiff = Math.abs(screenResolution.x * supportedHeight - supportedWidth * screenResolution.y);
      if (newDiff == 0) {
        bestSize = new Point(supportedWidth, supportedHeight);
        break;
      }
      //更新最小差值
      if (newDiff < diff) {
        bestSize = new Point(supportedWidth, supportedHeight);
        diff = newDiff;
      }
    }
    //若是還沒找到,就使用預覽值
    if (bestSize == null) {
      Camera.Size defaultSize = parameters.getPreviewSize();
      bestSize = new Point(defaultSize.width, defaultSize.height);
    }
    return bestSize;
  }

zxing中是根據實際屏幕值,根設備支持的尺寸交叉相乘,獲取差值最小設爲最合適的值,若是沒有使用預覽值。

zxing使用方法比較簡單些。
相關文章
相關標籤/搜索