memfis19/Annca

Zoom photo preview

freakdragon opened this issue · 3 comments

Trying to add slider zoomer to Camera for photos.
Added to CameraController:

float getCurrentZoom();
void setCurrentZoom(float zoom);
float getMaxZoom();

Added to Camera1Controller

@Override
    public float getCurrentZoom() {
        return cameraManager.getCurrentZoom();
    }
    @Override
    public float getMaxZoom() {
        return cameraManager.getMaxZoom();
    }
    @Override
    public void setCurrentZoom(float zoom) {
        cameraManager.setCurrentZoom(zoom);
    }

Added to Camera2Controller

      @Override
    public float getCurrentZoom() {
        return camera2Manager.getCurrentZoom();
    }
    @Override
    public float getMaxZoom() {
        return camera2Manager.getMaxZoom();
    }
    @Override
    public void setCurrentZoom(float zoom) {
        camera2Manager.setCurrentZoom(zoom);
    }

Added to CameraManager

    float getCurrentZoom();
    void setCurrentZoom(float zoom);
    float getMaxZoom();

Added to AnncaCameraActivity

protected float getCurrentZoom() {
        return getCameraController().getCurrentZoom();
    }
    protected float getMaxZoom() {
        return getCameraController().getMaxZoom();
    }
    protected void setCurrentZoom(float zoom) {
        getCameraController().setCurrentZoom(zoom);
    }

I'm getting value of it by max zoom of camera1

Camera.Parameters parameter = camera.getParameters();
        if(parameter.isZoomSupported()) {
            return parameter.getMaxZoom();
        }

and camera2

(manager.getCameraCharacteristics(this.currentCameraId).get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM))*10

SeekBar impementation:

minZoom = getMinZoom();
        maxZoom = getMaxZoom() - 1;
        final int step = 1;
        seekBarBottom.setMax(Math.round(maxZoom - minZoom));
        seekBarBottom.setOnSeekBarChangeListener(
                new SeekBar.OnSeekBarChangeListener()
                {
                    @Override
                    public void onStopTrackingTouch(SeekBar seekBar) {}
                    @Override
                    public void onStartTrackingTouch(SeekBar seekBar) {}
                    @Override
                    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {                        
                        setCurrentZoom(Math.round(minZoom + (progress * step)));
                    }
                }
        );

I've added to Camera1Manager

public void setCurrentZoom(float zoom) {
        Camera.Parameters parameter = camera.getParameters();
        if(getCurrentZoom() < getMaxZoom()) {
            parameter.setZoom(Math.round(zoom));
            camera.setParameters(parameter);
        }
    }

Works fine.

I've added to Camera2Manager

protected int zoomLevel = 1;
public void setCurrentZoom(float zoomLevel) {
        try {
            CameraCharacteristics characteristics = manager.getCameraCharacteristics(this.currentCameraId);
            float maxZoom = (characteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM))*10;
            Rect m = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
            if((zoomLevel <= maxZoom) && (zoomLevel > 1)) {
                int minW = (int) (m.width() / maxZoom);
                int minH = (int) (m.height() / maxZoom);
                int difW = m.width() - minW;
                int difH = m.height() - minH;
                int cropW = difW / 100 * (int) zoomLevel;
                int cropH = difH / 100 * (int) zoomLevel;
                cropW -= cropW & 3;
                cropH -= cropH & 3;
                Rect zoom = new Rect(cropW, cropH, m.width() - cropW, m.height() - cropH);
                try {
                    previewRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, zoom);
                    captureSession.capture(previewRequestBuilder.build(), captureCallback, backgroundHandler);
                } catch (Exception e) {
                    Log.e(TAG, "Error updating preview: ", e);
                }
                this.zoomLevel = (int) zoomLevel;
            }
        } catch (Exception e) {
            Log.e(TAG, "Error during camera init");
        }
    }

It zooms but immediately returns to normal state. Is there some listener that changes its state back?

changed
captureSession.capture(previewRequestBuilder.build(), captureCallback, backgroundHandler);
to
captureSession.setRepeatingRequest(previewRequestBuilder.build(), captureCallback, backgroundHandler);
and it worked.
Now I'm fighting with zoom. It doesn't crop zoomed image. I'll write again, if I'll gain a victory

Hi, I'll take a look, thank you for reporting.

changed function in Camera2Manager to

@Override
    public void setCurrentZoom(float zoomLevel) {
        Rect zoomRect = getZoomRect(zoomLevel);
        if(zoomRect != null) {
            try {
                previewRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, zoomRect);
                captureSession.setRepeatingRequest(previewRequestBuilder.build(), captureCallback, backgroundHandler);
            } catch (Exception e) {
                Log.e(TAG, "Error updating preview: ", e);
            }
            this.zoomLevel = (int) zoomLevel;
        }
    }

    private Rect getZoomRect(float zoomLevel) {
        try {
            CameraCharacteristics characteristics = manager.getCameraCharacteristics(this.currentCameraId);
            float maxZoom = (characteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM)) * 10;
            Rect activeRect = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
            if((zoomLevel <= maxZoom) && (zoomLevel > 1)) {
                int minW = (int) (activeRect.width() / maxZoom);
                int minH = (int) (activeRect.height() / maxZoom);
                int difW = activeRect.width() - minW;
                int difH = activeRect.height() - minH;
                int cropW = difW / 100 * (int) zoomLevel;
                int cropH = difH / 100 * (int) zoomLevel;
                cropW -= cropW & 3;
                cropH -= cropH & 3;
                return new Rect(cropW, cropH, activeRect.width() - cropW, activeRect.height() - cropH);
            } else if(zoomLevel == 0){
                return new Rect(0, 0, activeRect.width(), activeRect.height());
            }
            return null;
        } catch (Exception e) {
            Log.e(TAG, "Error during camera init");
            return null;
        }
    }

and added cropping to CaptureStillPicture() function in Camera2Manager

private void captureStillPicture() {
        try {
            if (null == cameraDevice) {
                return;
            }
            final CaptureRequest.Builder captureBuilder =
                    cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
            captureBuilder.addTarget(imageReader.getSurface());

            captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
            captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getPhotoOrientation(configurationProvider.getSensorPosition()));

            Rect zoomRect = getZoomRect(zoomLevel);
            if(zoomRect == null) {
                zoomRect = getZoomRect(0);
            }
            captureBuilder.set(CaptureRequest.SCALER_CROP_REGION, zoomRect);
            
            CameraCaptureSession.CaptureCallback CaptureCallback = new CameraCaptureSession.CaptureCallback() {
                @Override
                public void onCaptureCompleted(@NonNull CameraCaptureSession session,
                                               @NonNull CaptureRequest request,
                                               @NonNull TotalCaptureResult result) {
                    Log.d(TAG, "onCaptureCompleted: ");
                }
            };

            captureSession.stopRepeating();
            captureSession.capture(captureBuilder.build(), CaptureCallback, null);
            setCurrentZoom(0);
        } catch (CameraAccessException e) {
            Log.e(TAG, "Error during capturing picture");
        }
    }

Works fine with photos (didn't try with video). Check it. And add zooming to this library if you want.
P.S. I'm setting zoom to 0, because zoom resets after taking photo. And that's why after take photo I'm setting my zoom seekbar's progress to 0 too. Don't know why it's so.