Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/camera/camera_android/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.10.11

* Adds `setJpegImageQuality` for controlling JPEG compression quality.

## 0.10.10+16

* Updates build files from Groovy to Kotlin.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
import io.flutter.plugins.camera.features.flash.FlashMode;
import io.flutter.plugins.camera.features.focuspoint.FocusPointFeature;
import io.flutter.plugins.camera.features.fpsrange.FpsRangeFeature;
import io.flutter.plugins.camera.features.jpegquality.JpegQualityFeature;
import io.flutter.plugins.camera.features.resolution.ResolutionFeature;
import io.flutter.plugins.camera.features.resolution.ResolutionPreset;
import io.flutter.plugins.camera.features.sensororientation.DeviceOrientationManager;
Expand Down Expand Up @@ -1416,6 +1417,20 @@ public void setDescriptionWhileRecording(CameraProperties properties) {
}
}

/**
* Sets the JPEG compression quality for still image capture.
*
* @param quality JPEG quality value between 1 and 100.
*/
public void setJpegImageQuality(@NonNull Long quality) {
JpegQualityFeature jpegQualityFeature = cameraFeatures.getJpegQuality();
if (jpegQualityFeature == null) {
jpegQualityFeature = cameraFeatureFactory.createJpegQualityFeature(cameraProperties);
cameraFeatures.setJpegQuality(jpegQualityFeature);
}
jpegQualityFeature.setValue(quality.intValue());
}

public void dispose() {
Log.i(TAG, "dispose");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,11 @@ public void setDescriptionWhileRecording(@NonNull String cameraName) {
}
}

@Override
public void setJpegImageQuality(@NonNull Long quality) {
camera.setJpegImageQuality(quality);
}

@Override
public void dispose() {
if (camera != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1079,6 +1079,9 @@ void create(
*/
void setDescriptionWhileRecording(@NonNull String description);

/** Sets the JPEG compression quality for still image capture. */
void setJpegImageQuality(@NonNull Long quality);

/** The codec used by CameraApi. */
static @NonNull MessageCodec<Object> getCodec() {
return PigeonCodec.INSTANCE;
Expand Down Expand Up @@ -1809,6 +1812,31 @@ public void error(Throwable error) {
channel.setMessageHandler(null);
}
}
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.camera_android.CameraApi.setJpegImageQuality"
+ messageChannelSuffix,
getCodec());
if (api != null) {
channel.setMessageHandler(
(message, reply) -> {
ArrayList<Object> wrapped = new ArrayList<>();
ArrayList<Object> args = (ArrayList<Object>) message;
Long qualityArg = (Long) args.get(0);
try {
api.setJpegImageQuality(qualityArg);
wrapped.add(0, null);
} catch (Throwable exception) {
wrapped = wrapError(exception);
}
reply.reply(wrapped);
});
} else {
channel.setMessageHandler(null);
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import io.flutter.plugins.camera.features.flash.FlashFeature;
import io.flutter.plugins.camera.features.focuspoint.FocusPointFeature;
import io.flutter.plugins.camera.features.fpsrange.FpsRangeFeature;
import io.flutter.plugins.camera.features.jpegquality.JpegQualityFeature;
import io.flutter.plugins.camera.features.noisereduction.NoiseReductionFeature;
import io.flutter.plugins.camera.features.resolution.ResolutionFeature;
import io.flutter.plugins.camera.features.resolution.ResolutionPreset;
Expand Down Expand Up @@ -157,4 +158,14 @@ ExposurePointFeature createExposurePointFeature(
*/
@NonNull
NoiseReductionFeature createNoiseReductionFeature(@NonNull CameraProperties cameraProperties);

/**
* Creates a new instance of the JPEG quality feature.
*
* @param cameraProperties instance of the CameraProperties class containing information about the
* cameras features.
* @return newly created instance of the JpegQualityFeature class.
*/
@NonNull
JpegQualityFeature createJpegQualityFeature(@NonNull CameraProperties cameraProperties);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import io.flutter.plugins.camera.features.flash.FlashFeature;
import io.flutter.plugins.camera.features.focuspoint.FocusPointFeature;
import io.flutter.plugins.camera.features.fpsrange.FpsRangeFeature;
import io.flutter.plugins.camera.features.jpegquality.JpegQualityFeature;
import io.flutter.plugins.camera.features.noisereduction.NoiseReductionFeature;
import io.flutter.plugins.camera.features.resolution.ResolutionFeature;
import io.flutter.plugins.camera.features.resolution.ResolutionPreset;
Expand Down Expand Up @@ -105,4 +106,10 @@ public NoiseReductionFeature createNoiseReductionFeature(
@NonNull CameraProperties cameraProperties) {
return new NoiseReductionFeature(cameraProperties);
}

@NonNull
@Override
public JpegQualityFeature createJpegQualityFeature(@NonNull CameraProperties cameraProperties) {
return new JpegQualityFeature(cameraProperties);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import android.app.Activity;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import io.flutter.plugins.camera.CameraProperties;
import io.flutter.plugins.camera.DartMessenger;
import io.flutter.plugins.camera.features.autofocus.AutoFocusFeature;
Expand All @@ -15,6 +16,7 @@
import io.flutter.plugins.camera.features.flash.FlashFeature;
import io.flutter.plugins.camera.features.focuspoint.FocusPointFeature;
import io.flutter.plugins.camera.features.fpsrange.FpsRangeFeature;
import io.flutter.plugins.camera.features.jpegquality.JpegQualityFeature;
import io.flutter.plugins.camera.features.noisereduction.NoiseReductionFeature;
import io.flutter.plugins.camera.features.resolution.ResolutionFeature;
import io.flutter.plugins.camera.features.resolution.ResolutionPreset;
Expand All @@ -41,6 +43,7 @@ public class CameraFeatures {
private static final String REGION_BOUNDARIES = "REGION_BOUNDARIES";
private static final String RESOLUTION = "RESOLUTION";
private static final String SENSOR_ORIENTATION = "SENSOR_ORIENTATION";
private static final String JPEG_QUALITY = "JPEG_QUALITY";
private static final String ZOOM_LEVEL = "ZOOM_LEVEL";

@NonNull
Expand Down Expand Up @@ -297,4 +300,23 @@ public ZoomLevelFeature getZoomLevel() {
public void setZoomLevel(@NonNull ZoomLevelFeature zoomLevel) {
this.featureMap.put(ZOOM_LEVEL, zoomLevel);
}

/**
* Gets the JPEG quality feature if it has been set.
*
* @return the JPEG quality feature, or null if not set.
*/
@Nullable
public JpegQualityFeature getJpegQuality() {
return (JpegQualityFeature) featureMap.get(JPEG_QUALITY);
}

/**
* Sets the instance of the JPEG quality feature.
*
* @param jpegQuality the {@link JpegQualityFeature} instance to set.
*/
public void setJpegQuality(@NonNull JpegQualityFeature jpegQuality) {
this.featureMap.put(JPEG_QUALITY, jpegQuality);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright 2013 The Flutter Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package io.flutter.plugins.camera.features.jpegquality;

import android.annotation.SuppressLint;
import android.hardware.camera2.CaptureRequest;
import androidx.annotation.NonNull;
import io.flutter.plugins.camera.CameraProperties;
import io.flutter.plugins.camera.features.CameraFeature;

/** Controls the JPEG compression quality on the {@link android.hardware.camera2} API. */
public class JpegQualityFeature extends CameraFeature<Integer> {
private int currentSetting = 100;

/**
* Creates a new instance of the {@link JpegQualityFeature}.
*
* @param cameraProperties Collection of characteristics for the current camera device.
*/
public JpegQualityFeature(@NonNull CameraProperties cameraProperties) {
super(cameraProperties);
}

@NonNull
@Override
public String getDebugName() {
return "JpegQualityFeature";
}

@SuppressLint("KotlinPropertyAccess")
@NonNull
@Override
public Integer getValue() {
return currentSetting;
}

@Override
public void setValue(@NonNull Integer value) {
this.currentSetting = value;
}

@Override
public boolean checkIsSupported() {
return true;
}

@Override
public void updateBuilder(@NonNull CaptureRequest.Builder requestBuilder) {
requestBuilder.set(CaptureRequest.JPEG_QUALITY, (byte) currentSetting);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The CaptureRequest.JPEG_QUALITY key expects an Integer value (type Key<Integer>). Casting currentSetting to byte will result in a Byte object being passed to the requestBuilder.set method due to autoboxing. This will cause a ClassCastException at runtime because a Byte cannot be cast to an Integer.

Suggested change
requestBuilder.set(CaptureRequest.JPEG_QUALITY, (byte) currentSetting);
requestBuilder.set(CaptureRequest.JPEG_QUALITY, currentSetting);

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import io.flutter.plugins.camera.features.flash.FlashMode;
import io.flutter.plugins.camera.features.focuspoint.FocusPointFeature;
import io.flutter.plugins.camera.features.fpsrange.FpsRangeFeature;
import io.flutter.plugins.camera.features.jpegquality.JpegQualityFeature;
import io.flutter.plugins.camera.features.noisereduction.NoiseReductionFeature;
import io.flutter.plugins.camera.features.resolution.ResolutionFeature;
import io.flutter.plugins.camera.features.resolution.ResolutionPreset;
Expand Down Expand Up @@ -1468,5 +1469,10 @@ public NoiseReductionFeature createNoiseReductionFeature(
@NonNull CameraProperties cameraProperties) {
return mockNoiseReductionFeature;
}

@Override
public JpegQualityFeature createJpegQualityFeature(@NonNull CameraProperties cameraProperties) {
return mock(JpegQualityFeature.class);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import io.flutter.plugins.camera.features.flash.FlashFeature;
import io.flutter.plugins.camera.features.focuspoint.FocusPointFeature;
import io.flutter.plugins.camera.features.fpsrange.FpsRangeFeature;
import io.flutter.plugins.camera.features.jpegquality.JpegQualityFeature;
import io.flutter.plugins.camera.features.noisereduction.NoiseReductionFeature;
import io.flutter.plugins.camera.features.resolution.ResolutionFeature;
import io.flutter.plugins.camera.features.resolution.ResolutionPreset;
Expand Down Expand Up @@ -200,5 +201,10 @@ public NoiseReductionFeature createNoiseReductionFeature(
@NonNull CameraProperties cameraProperties) {
return mockNoiseReductionFeature;
}

@Override
public JpegQualityFeature createJpegQualityFeature(@NonNull CameraProperties cameraProperties) {
return mock(JpegQualityFeature.class);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright 2013 The Flutter Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package io.flutter.plugins.camera.features.jpegquality;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

import android.hardware.camera2.CaptureRequest;
import io.flutter.plugins.camera.CameraProperties;
import org.junit.Test;

public class JpegQualityFeatureTest {
@Test
public void getDebugName_shouldReturnTheNameOfTheFeature() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
JpegQualityFeature jpegQualityFeature = new JpegQualityFeature(mockCameraProperties);

assertEquals("JpegQualityFeature", jpegQualityFeature.getDebugName());
}

@Test
public void getValue_shouldReturn100IfNotSet() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
JpegQualityFeature jpegQualityFeature = new JpegQualityFeature(mockCameraProperties);

assertEquals(Integer.valueOf(100), jpegQualityFeature.getValue());
}

@Test
public void getValue_shouldEchoTheSetValue() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
JpegQualityFeature jpegQualityFeature = new JpegQualityFeature(mockCameraProperties);

jpegQualityFeature.setValue(50);
assertEquals(Integer.valueOf(50), jpegQualityFeature.getValue());
}

@Test
public void checkIsSupported_shouldReturnTrue() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
JpegQualityFeature jpegQualityFeature = new JpegQualityFeature(mockCameraProperties);

assertTrue(jpegQualityFeature.checkIsSupported());
}

@Test
public void updateBuilder_shouldSetJpegQualityOnBuilder() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class);
JpegQualityFeature jpegQualityFeature = new JpegQualityFeature(mockCameraProperties);

jpegQualityFeature.setValue(75);
jpegQualityFeature.updateBuilder(mockBuilder);

verify(mockBuilder, times(1)).set(CaptureRequest.JPEG_QUALITY, (byte) 75);
}

@Test
public void updateBuilder_shouldSetDefaultQualityWhenNotExplicitlySet() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class);
JpegQualityFeature jpegQualityFeature = new JpegQualityFeature(mockCameraProperties);

jpegQualityFeature.updateBuilder(mockBuilder);

verify(mockBuilder, times(1)).set(CaptureRequest.JPEG_QUALITY, (byte) 100);
}
}
2 changes: 1 addition & 1 deletion packages/camera/camera_android/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ dependencies:
# The example app is bundled with the plugin so we use a path dependency on
# the parent directory to use the current plugin's version.
path: ../
camera_platform_interface: ^2.6.0
camera_platform_interface: ^2.13.0
flutter:
sdk: flutter
path_provider: ^2.0.0
Expand Down
4 changes: 4 additions & 0 deletions packages/camera/camera_android/lib/src/android_camera.dart
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,10 @@ class AndroidCamera extends CameraPlatform {
await _hostApi.setDescriptionWhileRecording(description.name);
}

@override
Future<void> setJpegImageQuality(int cameraId, int quality) =>
_hostApi.setJpegImageQuality(quality);

@override
Widget buildPreview(int cameraId) {
return Texture(textureId: cameraId);
Expand Down
Loading