diff --git a/README.md b/README.md index 505b36e1..f4f616c3 100644 --- a/README.md +++ b/README.md @@ -4,16 +4,16 @@ - lots *of serious bugs fixed, I have lost the count* - *decent orientation support for both pictures and videos* - *EXIF support* -- *simpler APIs* -- *docs and comments in code* -- *introduced sessionType (picture or video), replacing Method and Permissions stuff* +- *real tap-to-focus support* +- *simpler APIs, docs and heavily commented code* +- *replacing Method and Permissions stuff with `sessionType`* - *new `captureSnapshot` API* - *new `setLocation` and `setWhiteBalance` APIs* +- *new `setGrid` APIs, to draw 3x3, 4x4 or golden ratio grids - *option to pass a `File` when recording a video* -- *introduced a smart measuring and sizing behavior, replacing bugged `adjustViewBounds`* +- *smart measuring and sizing behavior, replacing bugged `adjustViewBounds`* - *measure `CameraView` as center crop or center inside* - *add multiple `CameraListener`s for events* -- *new `setGrid` APIs, to draw 3x3, 4x4 or golden ratio grids *Feel free to open issues with suggestions or contribute.* diff --git a/camerakit/src/main/api16/com/flurgle/camerakit/Camera1.java b/camerakit/src/main/api16/com/flurgle/camerakit/Camera1.java index 3fe2a7a3..59f01ba3 100644 --- a/camerakit/src/main/api16/com/flurgle/camerakit/Camera1.java +++ b/camerakit/src/main/api16/com/flurgle/camerakit/Camera1.java @@ -31,8 +31,6 @@ class Camera1 extends CameraImpl { private static final String TAG = Camera1.class.getSimpleName(); - private static final int FOCUS_AREA_SIZE_DEFAULT = 200; - private static final int FOCUS_METERING_AREA_WEIGHT_DEFAULT = 1000; private static final int DELAY_MILLIS_BEFORE_RESETTING_FOCUS = 3000; private int mCameraId; @@ -672,17 +670,16 @@ class Camera1 extends CameraImpl { if (!mFocusOnTap) return; if (mCamera == null) return; if (event.getAction() != MotionEvent.ACTION_UP) return; - Rect rect = calculateFocusArea(event.getX(), event.getY()); - List meteringAreas = new ArrayList<>(); - meteringAreas.add(new Camera.Area(rect, getFocusMeteringAreaWeight())); - + List meteringAreas2 = computeMeteringAreas(event.getX(), event.getY()); + List meteringAreas1 = meteringAreas2.subList(0, 1); synchronized (mLock) { Camera.Parameters parameters = mCamera.getParameters(); boolean autofocusSupported = parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_AUTO); if (autofocusSupported) { - if (parameters.getMaxNumFocusAreas() > 0) parameters.setFocusAreas(meteringAreas); - if (parameters.getMaxNumMeteringAreas() > 0) - parameters.setMeteringAreas(meteringAreas); + int maxAF = parameters.getMaxNumFocusAreas(); + int maxAE = parameters.getMaxNumMeteringAreas(); + if (maxAF > 0) parameters.setFocusAreas(maxAF > 1 ? meteringAreas2 : meteringAreas1); + if (maxAE > 0) parameters.setMeteringAreas(maxAE > 1 ? meteringAreas2 : meteringAreas1); parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); mCamera.setParameters(parameters); mCamera.autoFocus(new Camera.AutoFocusCallback() { @@ -696,15 +693,6 @@ class Camera1 extends CameraImpl { } - private int getFocusAreaSize() { - return FOCUS_AREA_SIZE_DEFAULT; - } - - - private int getFocusMeteringAreaWeight() { - return FOCUS_METERING_AREA_WEIGHT_DEFAULT; - } - private void resetFocus(final boolean success, final Camera camera) { mFocusHandler.removeCallbacksAndMessages(null); @@ -730,30 +718,45 @@ class Camera1 extends CameraImpl { } - private Rect calculateFocusArea(float x, float y) { - int buffer = getFocusAreaSize() / 2; - int centerX = calculateCenter(x, mPreview.getView().getWidth(), buffer); - int centerY = calculateCenter(y, mPreview.getView().getHeight(), buffer); - return new Rect( - centerX - buffer, - centerY - buffer, - centerX + buffer, - centerY + buffer - ); + private List computeMeteringAreas(double viewClickX, double viewClickY) { + + // Event came in view coordinates. As far as I know, we must rotate to sensor coordinates. + // First, rescale to the -1000 ... 1000 range. + int displayToSensor = -computeSensorToDisplayOffset(); + double viewWidth = mPreview.getView().getWidth(); + double viewHeight = mPreview.getView().getHeight(); + viewClickX = -1000d + (viewClickX / viewWidth) * 2000d; + viewClickY = -1000d + (viewClickY / viewHeight) * 2000d; + + // Apply rotation to this point. + // https://academo.org/demos/rotation-about-point/ + double theta = ((double) displayToSensor) * Math.PI / 180; + double sensorClickX = viewClickX * Math.cos(theta) - viewClickY * Math.sin(theta); + double sensorClickY = viewClickX * Math.sin(theta) + viewClickY * Math.cos(theta); + Log.e(TAG, "viewClickX:"+viewClickX+", viewClickY:"+viewClickY); + Log.e(TAG, "sensorClickX:"+sensorClickX+", sensorClickY:"+sensorClickY); + + // Compute the rect bounds. + Rect rect1 = computeMeteringArea(sensorClickX, sensorClickY, 150d); + int weight1 = 1000; // 150 * 150 * 1000 = more than 10.000.000 + Rect rect2 = computeMeteringArea(sensorClickX, sensorClickY, 300d); + int weight2 = 100; // 300 * 300 * 100 = 9.000.000 + + List list = new ArrayList<>(2); + list.add(new Camera.Area(rect1, weight1)); + list.add(new Camera.Area(rect2, weight2)); + return list; } - private static int calculateCenter(float coord, int dimen, int buffer) { - int normalized = (int) ((coord / dimen) * 2000 - 1000); - if (Math.abs(normalized) + buffer > 1000) { - if (normalized > 0) { - return 1000 - buffer; - } else { - return -1000 + buffer; - } - } else { - return normalized; - } + private Rect computeMeteringArea(double centerX, double centerY, double size) { + double delta = size/2d; + int top = (int) Math.max(centerY - delta, -1000); + int bottom = (int) Math.min(centerY + delta, 1000); + int left = (int) Math.max(centerX - delta, -1000); + int right = (int) Math.min(centerX + delta, 1000); + // Log.e(TAG, "top:"+top+", left:"+left+", bottom:"+bottom+", right:"+right); + return new Rect(left, top, right, bottom); }